package com.hospital.diagnosis.module.hanlder;

import cn.hutool.core.bean.BeanUtil;
import com.hospital.common.base.ThreadAttributes;
import com.hospital.common.pojo.TChatLog;
import com.hospital.common.pojo.TChatSession;
import com.hospital.common.utils.LogUtils;
import com.hospital.common.utils.ThreadLocalUtils;
import com.hospital.diagnosis.module.dto.ChatDTO;
import com.hospital.diagnosis.module.exception.ServiceException;
import com.hospital.diagnosis.module.service.ChatService;
import com.hospital.diagnosis.module.utils.JsonUtils;
import com.hospital.diagnosis.module.utils.MinioUtils;
import com.hospital.diagnosis.module.utils.RedisUtils;
import com.hospital.diagnosis.module.vo.ChatVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import static com.hospital.common.enums.RoleType.PATIENT;
import static com.hospital.diagnosis.module.exception.enums.ExceptionCode.FORBIDDEN;
import static com.hospital.diagnosis.module.utils.WebSocketUtils.*;


@Component
public class ChatServerHandler extends TextWebSocketHandler
{
    @Autowired
    private ChatService chatService;
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private MinioUtils minioUtils;

    private static final Logger logger = LoggerFactory.getLogger(ChatServerHandler.class);

    /**
     * 连接建立后触发
     */
    //@OnOpen
    @Override
    public void afterConnectionEstablished(WebSocketSession session)
    {
        ThreadAttributes ta = ThreadLocalUtils.get();
        if(ta==null){
            throw new ServiceException(FORBIDDEN);
        }
        Long userId = ta.getUserId();
        SESSION_USER_MAPPER.put(session.getId(),userId);
        SESSION_ROLE_MAPPER.put(session.getId(),ta.getRoleType());
        ONLINE_USER_SESSIONS.put(userId,session);

        //获取会话列表
        List<TChatSession> chats= new ArrayList<>(chatService.getChats(userId));
        chats.addAll(chatService.getArchivedChats(userId));
        ChatVo chatVo = new ChatVo(0,chatService.getChatSessionVo(chats));
        String chatsJson = JsonUtils.toJson(chatVo);
        sendMessage(session,chatsJson);
    }

    /**
     * 处理发送的消息
     */
    //@OnMessage
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage textMessage)
    {
        Long userId = SESSION_USER_MAPPER.get(session.getId());

        String message = textMessage.getPayload();
        ChatDTO chatDTO =JsonUtils.parse(message, ChatDTO.class);
        switch (chatDTO.getType()){
            case 0:
            {
                //更新会话列表
                List<TChatSession> chats= new ArrayList<>(chatService.getChats(userId));
                chats.addAll(chatService.getArchivedChats(userId));
                ChatVo chatVo = new ChatVo(0,chatService.getChatSessionVo(chats));
                String chatsJson = JsonUtils.toJson(chatVo);
                sendMessage(session,chatsJson);
                break;
            }
            case 1:
            {
                //接收单条消息
                if(ObjectUtils.isEmpty(chatDTO.getData())){
                    break;//忽略空消息
                }
                TChatLog chatLog=BeanUtil.toBean(chatDTO.getData(), TChatLog.class);
                //TChatLog chatLog=(TChatLog) chatDTO.getData();
                if(ObjectUtils.isEmpty(redisUtils.hGet("chat", chatLog.getSessionId()))){
                    sendMessage(session,JsonUtils.toJson(new ChatVo(3,"本对话不存在或已经结束，请重新发起")));
                    break;
                }

                redisUtils.rPush("chatSessions:"+chatLog.getSessionId(),chatLog);

                WebSocketSession targetSession;
                TChatSession chatSession=(TChatSession) redisUtils.hGet("chat",chatLog.getSessionId());
                LogUtils.info("接收消息："+chatLog);
                LogUtils.info("目标会话："+chatSession);
                if(Objects.equals(chatLog.getSenderRole(), PATIENT.value)){
                    targetSession=getSession(chatSession.getDoctorId());
                }else{
                    targetSession=getSession(chatSession.getPatientId());
                }
                LogUtils.info("目标Session为空："+ (targetSession== null));

                //目标不在线，则未读计数加1
                if(ObjectUtils.isEmpty(targetSession)){
                    if(Objects.equals(chatLog.getSenderRole(), PATIENT.value)){
                        chatSession.setDoctorUnreadCount(chatSession.getDoctorUnreadCount()+1);
                    }else{
                        chatSession.setPatientUnreadCount(chatSession.getPatientUnreadCount()+1);
                    }
                    redisUtils.hSet("chat",chatSession.getSessionId(),chatSession);
                    break;
                }

                //转发消息
                if(chatLog.getMessageType()==1){
                    chatLog.setMediaDirPath(minioUtils.getPresignedUrl(chatLog.getMediaFile()));
                }else if(chatLog.getMessageType()==2){
                    chatLog.setMiscDirPath(minioUtils.getPresignedUrl(chatLog.getMiscFile()));
                }
                ChatVo chatVo = new ChatVo(1,chatLog);
                String chatsJson = JsonUtils.toJson(chatVo);
                LogUtils.info("转发消息："+chatsJson);
                sendMessage(targetSession,chatsJson);
                break;
            }
            case 2:
            {
                //传输消息对象列表
                String sessionId = (String) chatDTO.getData();
                if(ObjectUtils.isEmpty(sessionId)){
                    throw new ServiceException("会话ID传输错误");
                }
                if(ObjectUtils.isEmpty(redisUtils.hGet("chat",sessionId))){
                    List<TChatLog> chatLogs=chatService.getChatLogsBySessionId(sessionId);
                    if(ObjectUtils.isEmpty(chatLogs)){
                        sendMessage(session,JsonUtils.toJson(new ChatVo(3,"本对话不存在，请重新发起")));
                        break;
                    }
                    chatLogs.forEach(chatLog -> {
                        if(chatLog.getMessageType()==1){
                            chatLog.setMediaDirPath(minioUtils.getPresignedUrl(chatLog.getMediaFile()));
                        }else if(chatLog.getMessageType()==2){
                            chatLog.setMiscDirPath(minioUtils.getPresignedUrl(chatLog.getMiscFile()));
                        }
                    });
                    ChatVo chatVo = new ChatVo(2,chatLogs);
                    String chatLogsJson = JsonUtils.toJson(chatVo);
                    sendMessage(session,chatLogsJson);
                    break;
                }
                List chatLogs=redisUtils.getList("chatSessions:"+sessionId);
                List chatLogsList=chatLogs.stream().map(chatLog -> {
                    if(chatLog instanceof TChatLog){
                        TChatLog log=(TChatLog) chatLog;
                        if(log.getMessageType()==1){
                            log.setMediaDirPath(minioUtils.getPresignedUrl(log.getMediaFile()));
                        }else if(log.getMessageType()==2){
                            log.setMiscDirPath(minioUtils.getPresignedUrl(log.getMiscFile()));
                        }
                        return log;
                    }
                    return chatLog;
                }).toList();
                ChatVo chatVo = new ChatVo(2,chatLogsList);
                String chatLogsJson = JsonUtils.toJson(chatVo);
                sendMessage(session,chatLogsJson);

                //清除未读
                TChatSession chatSession=(TChatSession) redisUtils.hGet("chat",sessionId);
                if(Objects.equals(SESSION_ROLE_MAPPER.get(session.getId()), PATIENT.value)){
                    chatSession.setPatientUnreadCount(0);
                }else{
                    chatSession.setDoctorUnreadCount(0);
                }
                redisUtils.hSet("chat",chatSession.getSessionId(),chatSession);
                break;
            }
            default:
            {
                break;
            }
        }

    }

    /**
     * 连接关闭后触发
     */
    //@OnClose
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
        Long userId = SESSION_USER_MAPPER.get(session.getId());

        //当前的Session 移除
        SESSION_USER_MAPPER.remove(session.getId());
        SESSION_ROLE_MAPPER.remove(session.getId());
        ONLINE_USER_SESSIONS.remove(userId);
        //关闭当前连接
        try {
            session.close();
        } catch (Exception e) {
            logger.error("onClose error",e);
        }
    }

    /**
     * 处理会话产生的异常
     */
    //@OnError
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception)
    {
        try {
            session.close();
        } catch (Exception e) {
            logger.error("onError excepiton",e);
        }
        logger.info("Throwable msg "+exception.getMessage());
    }

}